using CHARACTERS;
using System.Collections.Generic;
using UnityEngine;
using static History.CharacterData.AnimationData;

namespace History
{
    [System.Serializable]
    public class CharacterData
    {
        public string characterName;
        public string displayName;
        public bool enabled;
        public Color color;
        public int priority;
        public bool isHighlighted;
        public bool isFacingLeft;
        public Vector2 positon;
        public CharacterConfigCache characterConfig;

        public string animationJSON;
        public string dataJSON;

        [System.Serializable]
        public class CharacterConfigCache
        {
            public string name;
            public string alias;

            public Character.CharacterType characterType;

            public Color nameColor;
            public Color dialogueColor;

            public string nameFont;
            public string dialogueFont;

            public float nameFontScale = 1f;
            public float dialogueFontScale = 1f;

            public CharacterConfigCache(CharacterConfigData reference)
            {
                name = reference.name;
                alias = reference.alias;
                characterType = reference.characterType;
                nameColor = reference.nameColor;
                dialogueColor = reference.dialogueColor;
                nameFont = FilePath.resource_font + reference.nameFont.name;
                dialogueFont = FilePath.resource_font + reference.dialogueFont.name;

                nameFontScale = reference.nameFontSize;
                dialogueFontScale = reference.dialogueFontSize;
            }
        }

        public static List<CharacterData> Capture()
        {
            List<CharacterData> characters = new List<CharacterData>();
            foreach(var character in CharacterManager.instance.allCharacters)
            {
                if (!character.isVisible)
                    continue;

                CharacterData entry = new CharacterData();
                entry.characterName = CharacterManager.instance.BacktrackingCharacterName(cloneName: character.name);
                entry.displayName = character.displayName;
                entry.enabled = character.isVisible;
                entry.priority = character.priority;
                entry.color = character.spriteColor;
                entry.isHighlighted = character.highlighted;
                entry.isFacingLeft = character.isFacingLeft;
                entry.positon = character.targetPosition;
                entry.characterConfig = new CharacterConfigCache(character.configData);
                entry.animationJSON = GetAnimationData(character);
                switch (character.configData.characterType)
                {
                    case Character.CharacterType.Sprite:
                    case Character.CharacterType.SpriteSheet:
                        SpriteData spriteData = new SpriteData();
                        spriteData.layers = new List<SpriteData.LayerData>();
                        SpritCharacter spritCharacter = character as SpritCharacter;
                        foreach(var layer in spritCharacter.layers)
                        {
                            var layerData = new SpriteData.LayerData();
                            layerData.color = layer.image.color;
                            layerData.spriteName = layer.image.sprite.name;
                            spriteData.layers.Add(layerData);
                        }
                        entry.dataJSON = JsonUtility.ToJson(spriteData);
                        break;
                    case Character.CharacterType.Live2D:
                        break;
                    case Character.CharacterType.Model3D:
                        break;
                }
                characters.Add(entry);
            }
            return characters;
        }

        public static void Apply(List<CharacterData> datas)
        {
            List<string> cache = new List<string>();
            foreach(CharacterData characterData in datas)
            {
                //Debug.Log($"{characterData.characterName} is applying");
                Character character = CharacterManager.instance.GetCharacter(characterData.characterName, createIfDoesNotExist: true,containCloneSymbol:true);
                character.displayName = characterData.displayName;
                character.SetColor(characterData.color);

                if (characterData.isHighlighted)
                    character.Highlight(immediate: true);
                else
                    character.Unhighlight(immediate: true);

                character.SetPriority(characterData.priority);

                if (characterData.isFacingLeft)
                    character.FaceLeft(immediate: true);
                else
                    character.FaceRight(immediate: false);

                character.SetPosition(characterData.positon);

                if (characterData.enabled)
                {
                    character.Show();
                }
                else
                {
                    character.Hide();
                }

                AnimationData animationData = JsonUtility.FromJson<AnimationData>( characterData.animationJSON);
                ApplyAnimationData(character, animationData);

                switch (character.configData.characterType)
                {
                    case Character.CharacterType.Sprite:
                    case Character.CharacterType.SpriteSheet:
                        SpriteData spriteData = JsonUtility.FromJson<SpriteData>(characterData.dataJSON);
                        SpritCharacter sc = character as SpritCharacter;
                        for(int i = 0;i < spriteData.layers.Count; i++)
                        {
                            var layer = spriteData.layers[i];
                            if(sc.layers[i].image.sprite != null && sc.layers[i].image.name != layer.spriteName)
                            {
                                Sprite sprite = sc.GetSprite(layer.spriteName);
                                if(sprite != null)
                                {
                                    //Debug.Log("call ");
                                    sc.SetSprite(sprite, i);
                                }
                                else
                                {
                                    Debug.LogWarning($"History State:could not load sprite '{layer.spriteName}'");
                                }
                            }
                        }
                        break;
                    case Character.CharacterType.Live2D:
                        break;
                    case Character.CharacterType.Model3D:
                            break;
                }
                cache.Add(character.name);
            }

            foreach(Character character in CharacterManager.instance.allCharacters)
            {
                if (!cache.Contains(character.name))
                    character.Cover();
            }
        }

        [System.Serializable]
        public class SpriteData
        {
            public List<LayerData> layers;
            [System.Serializable]
            public class LayerData
            {
                public string spriteName;
                public Color color;
            }
        }

        [System.Serializable]
        public class AnimationData
        {
            public List<AnimationParameter> parameters = new List<AnimationParameter>();

            [System.Serializable]
            public class AnimationParameter
            {
                public string name;
                public string type;
                public string value;
            }
        }

        private static string GetAnimationData(Character character)
        {
            Animator animator = character.animator;
            AnimationData data = new AnimationData();

            foreach(var param in animator.parameters)
            {
                if (param.type == AnimatorControllerParameterType.Trigger)
                    continue;
                AnimationParameter paraData = new AnimationParameter { name = param.name };
                switch (param.type) 
                {
                    case AnimatorControllerParameterType.Bool:
                        paraData.type = "Bool";
                        paraData.value = animator.GetBool(param.name).ToString();
                        break;
                    case AnimatorControllerParameterType.Float:
                        paraData.type = "Float";
                        paraData.value = animator.GetFloat(param.name).ToString();
                        break;
                    case AnimatorControllerParameterType.Int:
                        paraData.type = "Int";
                        paraData.value = animator.GetInteger(param.name).ToString();
                        break;
                }
                data.parameters.Add(paraData);
            }
            return JsonUtility.ToJson(data);
        }

        private static void ApplyAnimationData(Character character,AnimationData data)
        {
            Animator animator = character.animator;
            foreach(var param in data.parameters)
            {
                switch (param.type)
                {
                    case "Bool":
                        animator.SetBool(param.name, bool.Parse(param.value));
                        break;

                    case "Float":
                        animator.SetFloat(param.name, float.Parse(param.value));
                        break;

                    case "Int":
                        animator.SetInteger(param.name, int.Parse(param.value));
                        break;
                }
            }

            animator.SetTrigger(Character.DEFAULT_ANIMATIAN_REFRESH);
        }
   

    }
}